
#include <BQuater>
#include <BRender>
#include <BShape>
#include <BCamera>
#include "member_BCamera.h"

using namespace BWE;

#define member					(*(member_BCamera*)_ptr)
#define member_allocate()		_ptr = new member_BCamera(this)
#define member_release()		delete (member_BCamera*)_ptr

BCamera::BCamera(const BString& name) : BNode(name)
{
	member_allocate();
	member.pixmap = new IPixmap;
	member.center.set(0.0f, 1.0f, 0.0f);
}
BCamera::~BCamera()
{
	member_release();
}

void BCamera::setOrtho(bool ortho)
{
	if (member.ortho != ortho)
	{
		member.ortho = ortho;
		this->fresh();
	}
}
bool BCamera::ortho() const
{
	return member.ortho;
}

void BCamera::lookAt(float px, float py, float pz, float cx, float cy, float cz, float upx, float upy, float upz)
{
	lookAt(BVector(px, py, pz),	BVector(cx, cy, cz), BVector(upx, upy, upz));
}
void BCamera::lookAt(const BVector& position, const BVector& center, const BVector& up)
{
	this->setPosition(position);
	this->setCenter(center);
	this->setUp(up);
}

void BCamera::project(double fovy, double near, double far)
{
	member.fovy = fovy;
	member.near = near;
	member.far = far;
	member.adjust();
}
void BCamera::project(double fovy, double aspect, double near, double far)
{
	member.fovy = fovy;
	member.aspect = aspect;
	member.near = near;
	member.far = far;
	member.adjust();
}
void BCamera::project(double left, double right, double bottom, double top, double near, double far)
{
	member.left = left;
	member.right = right;
	member.bottom = bottom;
	member.top = top;
	member.near = near;
	member.far = far;

	double hh = (top - bottom) * 0.5;
	double hw = (right - left) * 0.5;
	double hfovy = atan(hh / member.near);
	member.fovy = hfovy * 2.0 / PI * 180.0;
	member.aspect = hw / hh;
	member.adjust();
}

void BCamera::setCenter(float x, float y, float z)
{
	setCenter(BVector(x, y, z));
}
void BCamera::setCenter(const BVector& center)
{
	if (member.center != center)
	{
		member.center = center;
		this->fresh();
	}
}
const BVector& BCamera::center() const
{
	return member.center;
}

void BCamera::setUp(const BVector& up)
{
	if (member.up != up)
	{
		member.up = up;
		this->fresh();
	}
}
void BCamera::setUp(float x, float y, float z)
{
	member.up.set(x, y, z);
}
const BVector& BCamera::up() const
{
	return member.up;
}

void BCamera::setLeft(double left)
{
	if (member.left != left)
	{
		member.left = left;
		this->fresh();
	}
}
double BCamera::left() const
{
	return member.left;
}

void BCamera::setRight(double right)
{
	if (member.right != right)
	{
		member.right = right;
		this->fresh();
	}
}
double BCamera::right() const
{
	return member.right;
}

void BCamera::setTop(double top)
{
	if (member.top != top)
	{
		member.top = top;
		this->fresh();
	}
}
double BCamera::top() const
{
	return member.top;
}

void BCamera::setBottom(double bottom)
{
	if (member.bottom != bottom)
	{
		member.bottom = bottom;
		this->fresh();
	}
}
double BCamera::bottom() const
{
	return member.bottom;
}

void BCamera::setNear(double near)
{
	if (member.near != near)
	{
		member.near = near;
		member.adjust();
	}
}
double BCamera::near() const
{
	return member.near;
}

void BCamera::setFovy(double fovy)
{
	if (member.fovy != fovy)
	{
		member.fovy = fovy;
		member.adjust();
	}
}
double BCamera::fovy() const
{
	return member.fovy;
}

void BCamera::setAspect(double aspect)
{
	if (member.aspect != aspect)
	{
		member.aspect = aspect;
		member.adjust();
	}
}
double BCamera::aspect() const
{
	return member.aspect;
}

void BCamera::setFar(double far)
{
	if (member.far != far)
	{
		member.far = far;
		this->fresh();
	}
}
double BCamera::far() const
{
	return member.far;
}

void BCamera::setPixelSize(int pixelWidth, int pixelHeight)
{
	setPixelSize(BSize(pixelWidth, pixelHeight));
}
void BCamera::setPixelSize(const BSize& pixelSize)
{
	if (member.pixmap->size() != pixelSize)
	{
		member.pixmap->setSize(pixelSize);
		this->fresh();
	}
}
const BSize& BCamera::pixelSize() const
{
	return member.pixmap->size();
}

void BCamera::setPhotoImage(BImage* photoImage)
{
	if (member.photoImage != photoImage)
	{
		member.photoImage = photoImage;
		this->fresh();
	}
}
const BImage* BCamera::photoImage() const
{
	return member.photoImage;
}
BImage* BCamera::photoImage()
{
	return member.photoImage;
}

void BCamera::fresh() const
{
	member.refresh = true;
}

bool BCamera::query(const char* name, const BValue& value) const
{
	if (0 == strcmp(name, "frustum"))
	{
		BVectorArray& points = value;
		points.reset();
		points.append(member.frustum.near_v0);
		points.append(member.frustum.near_v1);
		points.append(member.frustum.near_v2);
		points.append(member.frustum.near_v3);
		points.append(member.frustum.far_v0);
		points.append(member.frustum.far_v1);
		points.append(member.frustum.far_v2);
		points.append(member.frustum.far_v3);
		return true;
	}
	if (0 == strcmp(name, "lights"))
	{
		BLightArray& lights = value;
		lights = member.lights;
		return true;
	}
	if (0 == strcmp(name, "shapes"))
	{
		BMap<BShape*, BBox>* shapeMap = value;
		shapeMap->reset();
		for (int i = 0; i < member.shapeArray.size(); i++)
		{
			ShapeInfo& sinfo = member.shapeArray[i];
			BShape* shape = sinfo.shape;
			shapeMap->insert(shape, sinfo.box);
		}
	}
	if (0 == strcmp(name, "transShapes"))
	{
		BMap<BShape*, BBox>* transShapeQueue = value;
		transShapeQueue->reset();
		for (auto it = member.transShapeQueue.begin(); it.valid(); it++)
		{
			ShapeInfo& sinfo = *it;
			BShape* shape = sinfo.shape;
			transShapeQueue->insert(shape, sinfo.box);
		}
	}
	return false;
}

